package com.gnerv.battle.boot.module.base.autoconfigure;

import com.gnerv.battle.boot.module.base.model.dto.AccountDetailsDTO;
import com.gnerv.battle.boot.module.base.service.AccountService;
import com.gnerv.battle.boot.module.base.service.CurrentAccountService;
import com.gnerv.battle.boot.module.base.service.PasswordService;
import com.gnerv.battle.boot.module.base.service.PermissionService;
import com.gnerv.battle.boot.security.autoconfigure.BattleSecurityAutoConfiguration;
import com.gnerv.battle.boot.security.model.LoginAccountDetails;
import com.gnerv.battle.boot.security.service.AbstractUrlPermissionService;
import com.gnerv.battle.boot.security.tool.SecurityTools;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.List;
import java.util.Set;

/**
 * @author Gnerv LiGen
 */
@Slf4j
@Configuration
@ConditionalOnClass(value = {UserDetailsService.class, PasswordEncoder.class, AbstractUrlPermissionService.class})
@AutoConfigureBefore({BattleSecurityAutoConfiguration.class, BattleBaseAutoConfiguration.class})
@EnableConfigurationProperties
public class BattleBaseSecurityAutoConfiguration {

    @Bean
    public CurrentAccountService currentAccountService() {
        return new CurrentAccountService() {
            @Override
            public String username() {
                LoginAccountDetails accountDetails = SecurityTools.accountDetails();
                return accountDetails.getUsername();
            }

            @Override
            public String accountUkId() {
                LoginAccountDetails accountDetails = SecurityTools.accountDetails();
                return accountDetails.getUkId();
            }

            @Override
            public Set<String> roleUkIdList() {
                LoginAccountDetails accountDetails = SecurityTools.accountDetails();
                return accountDetails.getRoleUkIdList();
            }
        };
    }

    @Bean
    public PasswordService passwordService(PasswordEncoder passwordEncoder) {
        return passwordEncoder::encode;
    }

    @Bean
    public UserDetailsService userDetailsService(AccountService accountService) {
        return username -> {
            AccountDetailsDTO accountDetailsDTO = accountService.selectLoginByUsername(username);
            if (accountDetailsDTO == null) {
                throw new UsernameNotFoundException(username);
            }
            List<GrantedAuthority> grantedAuthorities = AuthorityUtils.createAuthorityList(accountDetailsDTO.getPermissionValueSet());
            LoginAccountDetails loginAccountDetails = new LoginAccountDetails(accountDetailsDTO.getUsername(), accountDetailsDTO.getPassword(), grantedAuthorities);
            loginAccountDetails.setUkId(accountDetailsDTO.getUkId());
            loginAccountDetails.setRoleUkIdList(accountDetailsDTO.getRoleUkIdSet());
            return loginAccountDetails;
        };
    }

    @Bean
    public AbstractUrlPermissionService urlPermissionService(PermissionService permissionService) {
        return new AbstractUrlPermissionService() {
            @Override
            public String selectPermission(String url, String type) {
                return permissionService.selectValueByUrlAndType(url, type);
            }
        };
    }

}
